package org.datasetcreator.reader.test;

import java.io.File;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.datasetcreator.reader.EntityGenerator;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.Table;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class PlayWithHibernateConf {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException,
			InstantiationException, HibernateException, SQLException,
			SecurityException, NoSuchFieldException {

		File confFile = new File(PlayWithHibernateConf.class.getResource(
				"../hibernate.cfg.xml").getFile());
		File baseDir = confFile.getParentFile();

		if (!baseDir.exists() || !confFile.exists()) {
			throw new IllegalStateException(
					"Configutation file or mapping directory does not exist");
		}

		Configuration conf = new Configuration();

		System.out.println("Loading Configuration");
		conf.configure(confFile);

		System.out.println("Adding Mappings");
		conf.addDirectory(baseDir);

		System.out.println("Building mappings");
		conf.buildMappings();

		SchemaExport schemaExp = new SchemaExport(conf);
		schemaExp.create(true, false);
		for (Object obj : schemaExp.getExceptions()) {
			System.out.println("-------------------->" + obj.toString());
		}
		System.out.println("Opening Session");
		SessionFactory sessionFactory = conf.buildSessionFactory();
		Session session = sessionFactory.openSession();

		String initialQuery = "CALL CSVWRITE('";
		String middleQuery = "', 'SELECT * FROM ";
		String endQuery = "')";
		// Create all base table files.
		String basePath = baseDir.getAbsolutePath();
		File tableFile = null;
		System.out.println("Going to create table files.......");
		Iterator tableMappingIterator = conf.getTableMappings();
		while (tableMappingIterator.hasNext()) {
			Table table = (Table) tableMappingIterator.next();
			tableFile = new File(basePath + "/" + table.getName() + ".csv");
			String queryString = initialQuery + tableFile + middleQuery
					+ table.getName() + endQuery;
			Query query = session.createSQLQuery(queryString);
			query.executeUpdate();

		}

		System.out.println("End of creation of table files");

		System.out.println("Flushing previous changes...");
		session.flush();
		System.out.println("Generating table content");
		EntityGenerator generator = EntityGenerator.getEntityGenerator();
		System.out.println("Generating main entities");
		Iterator classIterator = conf.getClassMappings();
		while (classIterator.hasNext()) {
			RootClass rootClass = (RootClass) classIterator.next();
			String className = rootClass.getClassName();
			Class loaded = Class.forName(className);
			generator.generateEntities(loaded, 3);
		}

		System.out.println("Generating collections entities");
		Iterator collectionIterator = conf.getCollectionMappings();
		while (collectionIterator.hasNext()) {
			Collection hibernateColl = (Collection) collectionIterator.next();
			// The class of the collection
			Class collectionClass = hibernateColl.getElement().getType()
					.getReturnedClass();
			List<Object> returned = generator.generateEntities(collectionClass,
					3);
			// the owner of the collection
			Class loaded = Class.forName(hibernateColl.getOwnerEntityName());
			for (Object toSet : generator.getEntitiesMap().get(loaded)) {
				
				String fieldName = hibernateColl.getNodeName();
				Field field = loaded.getDeclaredField(fieldName);
				if (!field.isAccessible()) {
					field.setAccessible(true);
				}
				Class type = field.getType();
				if (type.isAssignableFrom(Set.class)) {
					field.set(toSet, new HashSet(returned));
				} else if (type.isAssignableFrom(List.class)) {
					field.set(toSet, returned);
				}
			}
		}

		for (Class key : generator.getEntitiesMap().keySet()) {
			java.util.List objects = generator.getEntitiesMap().get(key);
			for (Object obj : objects) {
				session.saveOrUpdate(obj);
			}
		}
		session.flush();

		System.out.println("Going to create table files.......");
		tableMappingIterator = conf.getTableMappings();
		while (tableMappingIterator.hasNext()) {
			Table table = (Table) tableMappingIterator.next();
			tableFile = new File(basePath + "/" + table.getName() + ".csv");
			String queryString = initialQuery + tableFile + middleQuery
					+ table.getName() + endQuery;
			Query query = session.createSQLQuery(queryString);
			query.executeUpdate();

		}
		// session.flush();
		// session.disconnect();
		session.connection().commit();
		session.close();

		System.out.println("Closing resources...");
		sessionFactory.close();

	}
}
